/********************************************************************
* CopyPropagationFilter.cpp: Impletement class CopyPropagationFilter.
*
* Description:
*
* History:
*   Create: gxf. 2008-12-13
*   
*   Last Modified:
*
*******************************************************************/

#include "crossbit/VFilter.h"
#include "crossbit/VInst.h"
#include "crossbit/VBlock.h"
#include "crossbit/GLOBAL.h"
#include "crossbit/UTIL.h"

using namespace crossbit;

static inline void
new_cp_entry(VInst* inst, XTRegNum * activeCPTable, XTRegNum regNum, XTRegNum newReg){
    XTRegNum sreg = inst->getOperand(regNum).reg;
    XTRegNum mreg = inst->getOperand(newReg).reg;
    activeCPTable[sreg] = mreg;
}

static inline void 
delete_cp_entry(VInst* inst, XTRegNum * activeCPTable, XTRegNum regNum){
    XTRegNum reg = inst->getOperand(regNum).reg; 
    // If the reg content is modified, any copy mapping to this reg
    // should not be available
    XTRegNum i;
    for (i = 0; i < GLOBAL::MAX_VREG; i++){
        if (activeCPTable[i] = reg){
            activeCPTable[i] = GLOBAL::MAX_VREG + 1;
        }
    }
}

static inline void 
apply_cp_entry(VInst* inst, XTRegNum * activeCPTable, XTRegNum regNum){
    Operand oprnd = inst->getOperand(regNum);
    if(activeCPTable[oprnd.reg] != (GLOBAL::MAX_VREG + 1)){
        oprnd.reg = activeCPTable[oprnd.reg];
        inst->setOperand(regNum, oprnd);
    }
}

XTUint32 CopyPropagationFilter::run(VBlock *vb)
{
    VBlock::vb_iterator Itr = vb->begin(); 
    VBlock::vb_iterator End = vb->end(); 

    // This table records active copy pair
    XTRegNum activeCPTable[GLOBAL::MAX_VREG];
    UTIL::XTMemset(activeCPTable, GLOBAL::MAX_VREG + 1, sizeof(activeCPTable));

#define NEW_CP(regNum, newReg)    \
    new_cp_entry(inst, activeCPTable, regNum, newReg);

#define DELETE_CP(regNum)    \
    delete_cp_entry(inst, activeCPTable, regNum);

#define APPLY_CP(regNum)         \
    apply_cp_entry(inst, activeCPTable, regNum);

    while(Itr != End){
        XTRegNum sreg;
        XTRegNum vreg;
        XTRegNum vreg1, vreg2, vreg3, vreg4;

        VInst *inst = *Itr;

        switch(inst -> getOpcode())
        {
            case OP_LI:
                DELETE_CP(2);
                break;
            case OP_GET: 
                DELETE_CP(2);
                break;
            case OP_PUT: 
                APPLY_CP(1);
                break;
            case OP_MOV:
                APPLY_CP(1);
                DELETE_CP(2);
                NEW_CP(2, 1);
                break;
            case OP_LD: 
                APPLY_CP(1);
                DELETE_CP(4);
                break;
            case OP_ST:
                APPLY_CP(1);
                APPLY_CP(3);
                break;
            case OP_SEXT:
            case OP_ZEXT:
                APPLY_CP(1);
                DELETE_CP(3);
                break;
            case OP_NOT:
                APPLY_CP(1);
                DELETE_CP(2);
                break;
            case OP_ADDI:
                APPLY_CP(2);
                DELETE_CP(3);
                break;
            case OP_ADD:
            case OP_SUB:
            case OP_AND:
            case OP_XOR:
            case OP_OR:
            case OP_SLL:
            case OP_SRL:
            case OP_SRA:
                APPLY_CP(1);
                APPLY_CP(2);
                DELETE_CP(3);
                break;
            /* TODO: Seems not supported by translator yet
            case OP_SLLV:
                break;
            case OP_SRLV:
                break;
            case OP_SRAV:
                break; 
                */
            case OP_MUL:
            case OP_MULU:
            case OP_DIV:
            case OP_DIVU:
                APPLY_CP(1);
                APPLY_CP(2);
                DELETE_CP(3);
                DELETE_CP(4);
                break;
            case OP_CMP:
                APPLY_CP(2);
                APPLY_CP(3);
                DELETE_CP(4);
                break;
            case OP_JMP:
                APPLY_CP(1);
                break;
            case OP_BRANCH:
                APPLY_CP(2);
                APPLY_CP(3);
                APPLY_CP(4);
                break;
            // Nothing about reg
            case OP_SYSCALL:
            case OP_CALL:
            case OP_HALT:
                break;
            default: 
                // Unsupported inst in
          //      assert(0);
                break;
        }
        Itr++;
    }// while
    
	return (XTUint32)1;
}

